#_*_coding:utf-8_*_
'''
题目：
    剑指offer 15  二进制中1的个数

    请实现一个函数，输入一个整数（以二进制串形式），输出该数二进制表示中1的个数。
    例如，把9表示成二进制是 1001，有两位是1。因此，如果输入是9，则该函数输出2。


示例1：
    输入：00000000000000000000000000001011
    输出：3
    解释：输入的二进制串 00000000000000000000000000001011 中，共有三位为 '1'。

示例2：
    输入：00000000000000000000000010000000
    输出：1
    解释：输入的二进制串 00000000000000000000000010000000 中，共有一位为 '1'。

示例3：
    输入：11111111111111111111111111111101
    输出：31
    解释：输入的二进制串 11111111111111111111111111111101 中，共有 31 位为 '1'。
     

限制：
   输入必须是长度为 32 的 二进制串 。

'''
import collections

class Solution:
    def hammingWeight1(self, n: int) -> int:
        '''
            这里偷懒使用了Python自带的十进制转二进制的方法bin()
        '''
        binary_num = bin(n)[2:]
        count = 0
        for i in binary_num:
            if int(i) == 1:
                count += 1
        return count

    def hammingWeight2(self, n: int) -> int:
        '''
            这里更偷懒，使用了bin() 和 counter() 两个方法
        '''
        binary_num = bin(n)[2:]
        return collections.Counter(binary_num)['1']

    def hammingWeight3(self, n: int) -> int:
        '''
            逐位判断：
            根据与运算定义，设二进制数字n，则有：
                若 n&1 = 0，则 n 二进制最右一位为 1
                若 n&1 = 1，则 n 二进制最右一位为 0
            根据以上特点，考虑以下循环：
                1，判断 n 最右一位是否为1，根据结果计数
                2，将 n 右移一位（本题要求把数字 n 看做无符号数，因此使用无符号右移操作）

            算法流程：
                1，初始化数字统计变量 res = 0
                2，循环逐位判断：当 n=0 时跳出：
                    1， res += n & 1： 若 n&1 = 1，则统计数 res +1
                    2， n >>= 1：将二进制数字 n 无符号右移一位

            复杂度分析：
                时间复杂度O(log2n)：此算法循环内部仅有 移位，与，加等基本运算，占用O(1)，
                    诸位判断需要 log2n 次，其中 log2n 代表数字 n 最高位1的所在位数。
                空间复杂度O(1)：变量 res 使用常数大小额外空间
        '''
        res = 0
        while n:
            res += n&1
            n >>= 1
        return res

    def hammingWeight4(self, n: int) -> int:
        '''
            巧用n&(n-1)
            (n-1)解析：二进制数字 n 最右边的 1 变为 0，此 1右边的 0 都变为 1
            n&(n-1)解析：二进制数字 n 最右边的 1 变为 0，其余不变

            算法流程：
                1，初始化数量统计变量 res
                2，循环消去最右边的 1，当 n=0 时跳出
                    1， res += 1：统计变量加1
                    2，n &= n-1：消去数字 n最右边的 1
                3，返回统计数量 res
        '''
        res = 0
        while n:
            res += 1
            n &= n-1
        return res


